using Gj.Galaxy.Logic;
using Gj.MapData;
using Gj.MapData.Strategy;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Physics;
using Unity.Transforms;
using UnityEngine;
using BoxCollider = Unity.Physics.BoxCollider;
using CapsuleCollider = Unity.Physics.CapsuleCollider;
using SphereCollider = Unity.Physics.SphereCollider;

namespace Gj
{
    /// <summary>
    ///     对象基础control 网络层控制绑定
    /// </summary>
    public class BaseElement : MonoBehaviour, Element
    {
        public int index;
        public string key;
        public float destroyTime;

        public GameObject skin;

        public bool show;
        public bool exist;
        public bool auto;
        public bool debug;

        private GameObject _gameObject;

        private Skin _skin;

        private Transform _transform;
        
        [SerializeField]
        protected bool delayDestroy;

        protected Entity entity;

        public Transform Transform
        {
            get
            {
                if (_transform == null) _transform = transform;
                return _transform;
            }
        }

        public GameObject GameObject
        {
            get
            {
                if (_gameObject == null) _gameObject = gameObject;
                return _gameObject;
            }
        }

        public Skin Skin
        {
            get
            {
                if (_skin == null) _skin = skin.GetComponent<Skin>();
                return _skin;
            }
        }

        public int GetIndex()
        {
            return index;
        }

        public virtual object GetId()
        {
            return 0;
        }

        public virtual string GetKey()
        {
            return "";
        }

        public bool IsAuto()
        {
            return auto;
        }

        public bool IsDebug()
        {
            return debug;
        }

        public bool IsExist()
        {
            return exist;
        }

        public virtual void Show()
        {
            if (Skin != null) Skin.Show();
            show = true;
        }

        public virtual void Hide()
        {
            if (Skin != null) Skin.Hide();
            show = false;
        }

        float UnityObject.GetRadius()
        {
            return 0;
        }

        float UnityObject.GetHeight()
        {
            return 1;
        }

        Entity CoreObject.GetEntity()
        {
            return entity;
        }

        public string GetName()
        {
            return gameObject.name;
        }

        public Skin GetSkin()
        {
            return Skin;
        }

        public DataObject GetData()
        {
            return null;
        }

        public virtual int GetTotal()
        {
            return 1;
        }

        public virtual int GetNumber()
        {
            return 1;
        }

        public virtual Vector3 GetRealPosition()
        {
            return GetPosition();
        }

        public virtual Quaternion GetRealRotation()
        {
            return GetRotation();
        }

        public virtual Skin GetObject()
        {
            return Skin;
        }

        public virtual Skin GetObject(int i)
        {
            return Skin;
        }

        GameObject UnityObject.GetGameObject()
        {
            return GameObject;
        }

        public virtual Vector3 GetPosition()
        {
            return ObjectService.EntityManager.GetComponentData<LocalTransform>(entity).Position;
        }

        public virtual Quaternion GetRotation()
        {
            return ObjectService.EntityManager.GetComponentData<LocalTransform>(entity).Rotation;
        }

        public void SetPosition(Vector3 position)
        {
            var t = ObjectService.EntityManager.GetComponentData<LocalTransform>(entity);
            t.Position = position;
            ObjectService.EntityManager.AddComponentData(entity, t);
        }

        public void SetRotation(Quaternion rotation)
        {
            var t = ObjectService.EntityManager.GetComponentData<LocalTransform>(entity);
            t.Rotation = rotation;
            ObjectService.EntityManager.AddComponentData(entity, t);
        }

        public virtual void UpdatePosition(Vector3 position)
        {
            Transform.position = position;
        }

        public virtual void UpdateRotation(Quaternion rotation)
        {
            Transform.rotation = rotation;
        }

        public void Log(string t)
        {
            if (IsDebug() && IsExist()) LogTools.Info("{0} id->{1} index->{2} {3}", GetName(), GetId(), GetIndex(), t);
            if (IsDebug() && !IsExist()) LogTools.Error("{0} index->{2} {3}", GetName(), GetId(), GetIndex(), t);
        }

        public void DebugLog(string t)
        {
            LogTools.Error("{0} index->{2} {3}", GetName(), GetId(), GetIndex(), t);
        }

        /// <summary>
        ///     设置改对象的entity
        /// </summary>
        /// <param name="skinName"></param>
        protected void SetSkin(string skinName)
        {
            if (skin == null) skin = ObjectService.single.MakeSkin(skinName, gameObject);
        }

        protected virtual void ClearSkin()
        {
            if (skin != null) ObjectService.single.DestroyObj(skin);
            skin = null;
            _skin = null;
        }


        /// <summary>
        ///     自动创建对象插件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="pluginName"></param>
        /// <returns></returns>
        protected void SetPlugin<T>(ref T t, string pluginName) where T : Component
        {
            if (t == null)
            {
                t = ObjectService.single.MakePlugin<T>(pluginName, gameObject);
                t.gameObject.SetActive(true);
            }
        }

        /// <summary>
        ///     自动创建对象插件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="pluginName"></param>
        /// <returns></returns>
        protected void SetPlugin<T>(ref T t, string pluginName, GameObject obj) where T : Component
        {
            if (t == null)
            {
                t = ObjectService.single.MakePlugin<T>(pluginName, obj);
                t.gameObject.SetActive(true);
            }
        }

        protected void ClearPlugin<T>(ref T t) where T : Component
        {
            if (t != null)
            {
                t.gameObject.SetActive(false);
                ObjectService.single.DestroyObj(t.gameObject);
                t = null;
            }
        }

        protected void InitBase(BaseInfo baseInfo)
        {
            InitBase(baseInfo, entity);
        }

        /// <summary>
        ///     根据对象基础属性创建对象模型信息
        /// </summary>
        /// <param name="baseAttr"></param>
        protected void InitBase(BaseInfo baseInfo, Entity entity)
        {
            if (baseInfo.collider != ObjectCollider.Empty)
            {
                var physicsCollider = new PhysicsCollider();
                switch (baseInfo.collider)
                {
                    case ObjectCollider.Box:
                        physicsCollider.Value = BoxCollider.Create(new BoxGeometry
                        {
                            Orientation = quaternion.identity,
                            Center = new float3(baseInfo.centerX, baseInfo.centerY, baseInfo.centerZ),
                            Size = new float3(baseInfo.sizeX, baseInfo.sizeY, baseInfo.sizeZ)
                        });
                        break;
                    case ObjectCollider.Sphere:
                        physicsCollider.Value = SphereCollider.Create(new SphereGeometry
                        {
                            Center = new float3(baseInfo.centerX, baseInfo.centerY, baseInfo.centerZ),
                            Radius = baseInfo.radius
                        });
                        break;
                    case ObjectCollider.Capsule:
                        physicsCollider.Value = CapsuleCollider.Create(new CapsuleGeometry
                        {
                            Vertex0 = new float3(0, 0, 0),
                            Vertex1 = new float3(0, baseInfo.height, 0),
                            Radius = baseInfo.radius
                        });
                        break;
                }

                ObjectService.EntityManager.AddComponentData(entity, physicsCollider);
            }

            if (baseInfo.rigidbody)
            {
                var r = UnityTools.GetComponentRequire<Rigidbody>(gameObject);
                r.isKinematic = baseInfo.kinematic;
                r.useGravity = baseInfo.gravity;
                r.drag = Mathf.Infinity;
                r.angularDrag = Mathf.Infinity;
                r.constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationZ |
                                RigidbodyConstraints.FreezeRotationY;
            }
        }

        /// <summary>
        ///     初始化对象扩展属性
        /// </summary>
        /// <param name="objects"></param>
        protected virtual void FormatExtend(object[] objects)
        {
        }

        protected void InitInfo(ObjectInfo objectInfo, ObjectControl objectControl, GameObject obj)
        {
        }

        public virtual void OnInit()
        {
        }

        protected virtual void InitEntity()
        {
            if (entity == Entity.Null) entity = ObjectService.EntityManager.CreateEntity();
            ObjectService.EntityManager.AddComponentData(entity,
                new LocalTransform { Position = Transform.position, Rotation = Transform.rotation });
            OnInitEntity();
        }

        protected virtual void OnInitEntity()
        {
        }

        /// <summary>
        ///     创建对象初始化函数
        /// </summary>
        /// <param name="objectInfo"></param>
        /// <param name="control"></param>
        /// <param name="obj"></param>
        public void Init(int i)
        {
            index = i;
            exist = true;
            InitEntity();
            OnInit();
            // InitInfo(objectInfo, control, obj);
            // InitBase(detail.baseInfo);
            // SetSkin(objectInfo.skin);
            // FormatExtend(detail.extend);
        }

        public void Recovery()
        {
            OnRecovery();
            exist = false;
            Invoke("Destroy", delayDestroy ? destroyTime : 0);
        }

        protected virtual void OnRecovery()
        {
        }

        private void Destroy()
        {
            delayDestroy = false;
            if (!ObjectService.IsInWorld) return;
            OnDestroyElement();
            OnDestroyEntity();
        }

        protected virtual void OnDestroyElement()
        {
            ElementService.single.DestroyElement(this);
        }

        protected virtual void OnDestroyEntity()
        {
            ObjectService.EntityManager.DestroyEntity(entity);
            entity = Entity.Null;
        }

        public bool IsShow()
        {
            return show;
        }

        public virtual DefineData GetDefineData()
        {
            return null;
        }

        public virtual IdentityData GetIdentityData()
        {
            return null;
        }

        public virtual Vector2Int GetNode()
        {
            return Vector2Int.zero;
        }

        public virtual void Select()
        {
            
        }

        public virtual void Cancel()
        {
            
        }

        public virtual void OnMessage(EventMessage message)
        {
        }

        public void Log(string t, string s, params object[] p)
        {
            var text = string.Format(s, p);
            if (IsDebug() && IsExist())
                LogTools.Info("{0} id->{1} index->{2} {3} {4}", GetName(), GetId(), GetIndex(), t, text);
            if (IsDebug() && !IsExist()) LogTools.Error("{0} id->{1} index->{2} {3} {4}", GetName(), GetId(), GetIndex(), t, text);
        }

        public void DebugLog(string t, string s, params object[] p)
        {
            var text = string.Format(s, p);
            LogTools.Error("{0} id->{1} index->{2} {3} {4}", GetName(), GetId(), GetIndex(), t, text);
        }
    }
}